/*
 * Line.cpp
 *
 *  Created on: 2009-3-23
 *      Author: Songyp
 */

#include "Line.h"
#include "Ball.h"
#include <e32math.h>

CLine::CLine( TRealPoint aPoint1, TRealPoint aPoint2 ):iStart(aPoint1),iEnd(aPoint2)
	{
	}

void CLine::Initialize()
	{
	if( iStart.iX == iEnd.iX && iStart.iY == iEnd.iY )
		{
		return ;
		}
	if ( iStart.iX > iEnd.iX )
		{
		TRealPoint point = iStart;
		iStart = iEnd;
		iEnd = point;
		}
	if( iStart.iY == iEnd.iY )
		{
		iA = 0.0f;
		iB = 1.0f;
		}
	else if( iStart.iX == iEnd.iX )
		{
		iB = 0.0f;
		iA = 1.0f;
		}
	else
		{
		iB = 1.0f;
		iA = ( iStart.iY - iEnd.iY ) / ( iEnd.iX - iStart.iX );
		}
	iC = 0.0f - ( iA * iStart.iX + iB * iStart.iY );
	}

void CLine::ConstructL()
	{
	Initialize();
	}

CLine* CLine::NewL( TRealPoint aStart, TRealPoint aEnd )
	{
	CLine* self = new (ELeave)CLine( aStart, aEnd );
	CleanupStack::PushL( self );
	self->ConstructL();
	CleanupStack::Pop();
	return self;		
	}

TPoint CLine::GetStart()
	{
	return TPoint( iStart.iX, iStart.iY );
	}

void CLine::SetStart( TPoint aStart )
	{
	iStart.iX = aStart.iX;
	iStart.iY = aStart.iY;
	}

TPoint CLine::GetEnd()
	{
	return TPoint( iEnd.iX, iEnd.iY );
	}

void CLine::SetEnd( TPoint aEnd )
	{
	iEnd.iX = aEnd.iX;
	iEnd.iY = aEnd.iY;
	Initialize();
	}

TRealVector CLine::GetDir()
	{
	return TRealVector( iEnd.iX - iStart.iX, iEnd.iY - iStart.iY );
	}

TRealVector CLine::GetPerDic()
	{
	TRealVector dir = GetDir();
	if( dir.iX == 0.0f && dir.iY == 0.0f )
		{
		return TRealVector();		
		}
	if( dir.iY == 0.0f )
		{
		return TRealVector( 0.0f, 1.0f );
		}
	else
		{
		return TRealVector( 1.0f, ( 0.0f - dir.iX ) / dir.iY );
		}
	}

TInt CLine::GetY( TInt aX )
	{
	if( IsVertical() )
		{
		return 0;
		}
	return 0.0f - iC - iA*aX;
	}

TBool CLine::IsHorizonal()
	{
	return iA == 0.0f;
	}

TBool CLine::IsVertical()
	{
	return iB == 0.0f;
	}

TReal CLine::Distance( TPoint aPoint )
	{
	TReal dis = 0.0f;
	if( IsHorizonal() )
		{
		dis = aPoint.iY - GetY( aPoint.iX );
		}
	else if( IsVertical() )
		{
		dis = aPoint.iX - iStart.iX;
		}
	else 
		{
		TReal sqrtab;
		Math::Sqrt( sqrtab, iA*iA + iB*iB );
		dis = ( aPoint.iX * iA + aPoint.iY * iB + iC ) / sqrtab;
		}
	dis = ( dis >= 0.0f )? dis : ( 0.0f - dis );
	return dis;
	}

TBool CLine::Hit( CBall* aBall )
	{
	TPoint center( aBall->GetPos().iX, aBall->GetPos().iY );
	if( !IsVertical() && (center.iX <= iStart.iX || center.iX >= iEnd.iX ))
		{
		return EFalse;
		}
	TReal dist = Distance( center );
	return dist <= aBall->GetRad();
	}

TPoint CLine::GetPerFoot( TPoint aPoint )
	{
	if( IsHorizonal() )
		{
		return TPoint( aPoint.iX, iStart.iY );
		}
	if( IsVertical() )
		{
		return TPoint( iStart.iX, aPoint.iY );
		}
	TReal kk = 0.0f - 1.0f / iA;
	TReal xx = ( kk - aPoint.iY - iA ) / ( iA + kk );
	TReal yy = kk*xx - kk*aPoint.iX + aPoint.iY;
	return TPoint( xx, yy );
	}



